package com.taoz.rpc.core.server.tcp;

import com.taoz.rpc.core.model.RpcRequest;
import com.taoz.rpc.core.model.RpcResponse;
import com.taoz.rpc.core.serializer.Serializer;
import com.taoz.rpc.core.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProtocolMessage<T> {
    @Data
    public static class Header {
        private byte magic;  // 确认信息是否有效
        private byte version;  // 协议使用的版本
        private byte type;  // 消息类型
        private byte status;  // 消息状态
        private int length;  // 消息体长度
    }

    private Header header;
    private T body;  // 消息体

    public static ProtocolMessage<?> toMessage(Buffer buffer) {
        byte magic = buffer.getByte(0);
        if (magic != ProtocolConstant.MAGIC) {
            throw new RuntimeException("不合法的消息");
        }
        Header h = new Header();
        h.setMagic(buffer.getByte(0));
        h.setVersion(buffer.getByte(1));
        h.setType(buffer.getByte(2));
        h.setStatus(buffer.getByte(3));
        h.setLength(buffer.getInt(4));
        ProtocolMessage<?> message = null;
        try {
            byte[] bytes = buffer.getBytes(8, 8 + h.getLength());
            Serializer serializer = SerializerFactory.getSerializer();
            Class<?> clazz = h.getType() == ProtocolType.REQUEST ? RpcRequest.class : RpcResponse.class;
            message = new ProtocolMessage<>(h, serializer.deserialize(bytes, clazz));
        } catch (Exception e) {
            throw new RuntimeException("反序列化消息体失败");
        }
        return message;
    }

    public static Buffer toBuffer(ProtocolMessage<?> message) {
        Header header = message.getHeader();
        Object body = message.getBody();
        Buffer buffer = Buffer.buffer();
        buffer.appendByte(header.magic);
        buffer.appendByte(header.version);
        buffer.appendByte(header.type);
        buffer.appendByte(header.status);
        try {
            Serializer serializer = SerializerFactory.getSerializer();
            byte[] bytes = serializer.serialize(body);
            buffer.appendInt(bytes.length);
            buffer.appendBytes(bytes);
        } catch (Exception e) {
            log.info("序列化消息体失败", e);
            return null;
        }
        return buffer;
    }
}
